package hyPeerDriveTests;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Iterator;

import org.junit.Test;

import phase4Specification.testing.DepositBroadcastVisitor;
import phase4Specification.testing.TrackSendPathVisitor;
import dbPhase.hypeerweb.HyPeerWeb;
import dbPhase.hypeerweb.HyPeerWebDatabase;
import dbPhase.hypeerweb.Node;
import dbPhase.hypeerweb.Parameters;
import dbPhase.hypeerweb.SendVisitor;
import dbPhase.hypeerweb.SimplifiedNodeDomain;

public class CarlTests {
	public static HyPeerWeb hypeerweb = null;
	/*
	 * Testing Send
	 * 
	 * Equivalence partitioning
	 * 
	 * Equivalence in where you send to and from
	 * 1. Start is not in the hypeerweb
	 * 2. 0 <= start.webid < HyPeerWeb.size
	 * 
	 * 1. End is not in the hypeerweb
	 * 2. 0 <= end.webid < HyPeerWeb.size
	 * 
	 */
	
	@Test
	public void test() {
		HyPeerWebDatabase.initHyPeerWebDatabase();
		HyPeerWebDatabase.getSingleton().clear();
		hypeerweb = HyPeerWeb.getSingleton();
		//check a valid send
		assertTrue(testSend(5,3,0));
		
		//start outside the hypeerweb
		try{
			testSend(5,8,0);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		try{
			testSend(5,100,0);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		
		//start outside the hypeerweb
		try{
			testSend(5,5,0);
			assertTrue(false);
		
		}
		catch(Exception e){
			assertTrue(true);
		}
		
		//start from invalid node the hypeerweb
		try{
			testSend(5,-1,0);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		//send from an empty
		assertTrue(testSend(0,0,0));
		
		
		/*
		 * Send to outside the hypeerweb
		 */
		try{
			testSend(6,0,10);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		try{
			testSend(6,0,-1);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		try{
			testSend(0,0,-1);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
//
		try{
			testSend(0,0,10);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		try{
			testSend(-1,0,-1);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		try{
			testSend(15,0,-1);
			assertTrue(false);
		}
		catch(Exception e){
			assertTrue(true);
		}
		
		
		

	}
	static private void createHyPeerWebWith(int numberOfNodes) {
		hypeerweb.clear();
		Node node0 = new Node(0);
		hypeerweb.addToHyPeerWeb(node0, null);

		for (int i = 1; i < numberOfNodes; i++) {
			Node node = new Node(0);
			node0.addToHyPeerWeb(node);
		}
	}
	
	private static boolean sendVisitorErrorHeaderPrinted = false;

	@SuppressWarnings("unchecked")
	private static boolean testSend(int hypeerwebSize, int start,  int target) {
		createHyPeerWebWith(hypeerwebSize);

		TrackSendPathVisitor trackSendPathVisitor = new TrackSendPathVisitor();
		Parameters parameters = new Parameters();
		parameters.set(SendVisitor.TARGET_KEY, target);
		ArrayList<Integer> emptyList = new ArrayList<Integer>();
		parameters.set(TrackSendPathVisitor.PATH_KEY, emptyList);
		hypeerweb.getNode(start).accept(trackSendPathVisitor, parameters);

		ArrayList<ArrayList<Integer>> finalResult = (ArrayList<ArrayList<Integer>>) hypeerweb.getNode(target).getContents().get(TrackSendPathVisitor.PATHS_KEY);
		return checkFinalResult(finalResult, target);
	}
	
	private static boolean checkFinalResult(ArrayList<ArrayList<Integer>> paths, int target) {
		boolean result = true;
		for (ArrayList<Integer> path : paths) {
			//System.out.println("path"+path);
			int loc = checkFinalResultz(path, target);
			if (loc != -1) {
				result = false;
				if (!sendVisitorErrorHeaderPrinted) {
					System.out.println("-------------------------------------------------------------");
					System.out.println("Errors encountered while testing the SendVisitor");
				}
				sendVisitorErrorHeaderPrinted = false;
				System.out.print("    For the path: ");
				for (Integer i : path) {
					System.out.print(i + " ");
				}
				System.out.println(" there was a better choice than going from node "	+ path.get(loc) + " to " + path.get(loc + 1));
				System.out.println("    This was the first incorrect choice detected, there may be others");
			}
		}
		return result;
	}

	private static int checkFinalResultz(ArrayList<Integer> path, int targetId) {
		int result = -1;
		for (int i = 0; result == -1 && i < path.size() - 1; i++) {
			//System.out.print(result);
			if (!isBestChoice(path.get(i), path.get(i + 1), targetId)) {
				result = i;
			}
		}
		return result;
	}

	private static boolean isBestChoice(int source, int nextNode, int targetId) {
		SimplifiedNodeDomain sourceNode = hypeerweb.getNode(source).constructSimplifiedNodeDomain();
		boolean result = !sourceNode.containsCloserNode(nextNode, targetId);
		return result;
	}
	
	private static ArrayList<Integer> checkNodes(int i) {
		ArrayList<Integer> nodesNotVisited = new ArrayList<Integer>();

		int index = 0;
		Iterator<Node> iter = hypeerweb.iterator();
		while(iter.hasNext()){
			Node node = iter.next();
			if ((Integer) node.getContents().get(DepositBroadcastVisitor.DEPOSIT_KEY) != i) {
				nodesNotVisited.add(index);
			}
			index++;
		}

		return nodesNotVisited;
	}

	private static final int HYPEERWEB_SIZE = 32;
	private static final boolean VERBOSE = false;
}
